package pl.edu.pb.wi.pwnography.controller;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import pl.edu.pb.wi.pwnography.model.form.DiscretizationForm;
import pl.edu.pb.wi.pwnography.modules.Discretization;
import pl.edu.pb.wi.pwnography.session.FileList;

@Controller
@RequestMapping("/module/discretization")
public class DiscretizationModule {
    private static final Logger log = Logger
	    .getLogger(DiscretizationModule.class.getName());

    private static final String DISCRETIZATION_ERROR = "Wystąpił błąd w trakcie analizy. Może to być spowodowane niepoprawnym zestawem danych.";
    private static final String EQUAL_SIZE_SUCCESS = "Dyskretyzacja metodą równych przedziałów zakończyła się sukcesem. Dla kolumny %s oraz ilości przedziałów %d";
    private static final String EQUAL_SIZE_DESCRIPTION = "Dyskretyzacja metodą równych przedziałów dla kolumny %s oraz %d przedziałów.";
    private static final String LARGEST_CLASS_DESCRIPTION = "Dyskretyzacja metodą preferowania najliczniejszych klas dla kolumny %s oraz %d klas.";
    private static final String LARGEST_CLASS_SUCCESS = "Dyskretyzacja metodą preferowania najliczniejszych klas zakończyła się sukcesem. Dla kolumny %s oraz ilości klas %d";

    @Autowired
    private FileList fileList;

    public void setFileList(FileList fileList) {
	this.fileList = fileList;
    }

    @ModelAttribute("floatColumnList")
    public List<String> getFloatColumnNames() {
	return fileList.getActiveFile().getFloatTypeColumnNames();
    }

    @ModelAttribute("columnList")
    public List<String> getColumnNames() {
	return fileList.getActiveFile().getColumnNames();
    }

    @RequestMapping(value = "equalsize", method = RequestMethod.GET)
    public String equalSize(Model model) {
	log.info("Equal size discretization GET.");

	model.addAttribute("discretizationEqualSize", new DiscretizationForm());

	return "module/discretization/equalsize";
    }

    /*
     * Adnotacja @Valid pochodzi z JSR-303. Chodzi o to, aby działała walidacja
     * oparta na adnotacjach.
     */
    @RequestMapping(value = "equalsize", method = RequestMethod.POST)
    public String equalSize(
	    @ModelAttribute("discretizationEqualSize") @Valid DiscretizationForm discEqSize,
	    BindingResult results, Model model) {
	log.info("Equal size discretization POST.");

	if (results.hasErrors()) {
	    return "module/discretization/equalsize";
	}

	try {
	    Map<String, List<Object>> data = Discretization.equalSize(
		    discEqSize.getColumnName(), fileList.getActiveFile()
			    .getColumnValues(discEqSize.getColumnName()),
		    discEqSize.getNumberOfIntervals(), discEqSize
			    .getResultColumnName());

	    String description = String.format(EQUAL_SIZE_DESCRIPTION,
		    discEqSize.getColumnName(),
		    discEqSize.getNumberOfIntervals());

	    fileList.getActiveFile().addNewRevision(data, description);

	    log.info(fileList.getActiveFile().getCurrentRevisionData()
		    .toString());

	    model.addAttribute("successMsgs", Arrays
		    .asList(new String[] { String.format(EQUAL_SIZE_SUCCESS,
			    discEqSize.getColumnName(),
			    discEqSize.getNumberOfIntervals()) }));
	} catch (Exception e) {
	    log.info(String.format(
		    "Problem with equal size discretization. Exception: %s",
		    e.getMessage()));

	    model.addAttribute("errorMsgs",
		    Arrays.asList(new String[] { DISCRETIZATION_ERROR }));
	}

	return "module/discretization/equalsize";
    }

    @RequestMapping(value = "largestclass", method = RequestMethod.GET)
    public String largestClass(Model model) {
	log.info("Largest class discretization GET.");

	model.addAttribute("discretizationLargestClass",
		new DiscretizationForm());

	return "module/discretization/largestclass";
    }

    @RequestMapping(value = "largestclass", method = RequestMethod.POST)
    public String largestClass(
	    @ModelAttribute("discretizationLargestClass") @Valid DiscretizationForm discEqSize,
	    BindingResult results, Model model) {
	log.info("Largest class discretization POST.");

	if (results.hasErrors()) {
	    return "module/discretization/largestclass";
	}

	try {
	    Map<String, List<Object>> data = Discretization.largestClass(
		    discEqSize.getColumnName(), fileList.getActiveFile()
			    .getColumnValues(discEqSize.getColumnName()),
		    discEqSize.getNumberOfIntervals(), discEqSize
			    .getResultColumnName());

	    String description = String.format(LARGEST_CLASS_DESCRIPTION,
		    discEqSize.getColumnName(),
		    discEqSize.getNumberOfIntervals());

	    fileList.getActiveFile().addNewRevision(data, description);

	    log.info(fileList.getActiveFile().getCurrentRevisionData()
		    .toString());

	    model.addAttribute("successMsgs", Arrays
		    .asList(new String[] { String.format(LARGEST_CLASS_SUCCESS,
			    discEqSize.getColumnName(),
			    discEqSize.getNumberOfIntervals()) }));
	} catch (Exception e) {
	    log.info(String.format(
		    "Problem with equal size discretization. Exception: %s",
		    e.getMessage()));

	    model.addAttribute("errorMsgs",
		    Arrays.asList(new String[] { DISCRETIZATION_ERROR }));
	}

	return "module/discretization/largestclass";
    }
}
